from tkinter import messagebox


import myfuncBPH
import cv2
import numpy as np
import os #获得 dir
import math
from tkinter import *
import tkinter.filedialog
import tkinter.messagebox #这个是消息框，对话框的关键
from PIL import Image# BW 扩展 ，防止  H/W>2 ,右侧出现 轮廓检测 丢失。
import math
#socket
import socket
import threading
import time
import sys
# end socket


#
#s02  original img
#s03  255 single image
#s05  BW image
#s10

#s15  getShape8b() BPH_angle_operated:
#s22  LFsubImg

#s24  LF img  ,before little rotate ,
#s25  shift_right_down ,prepare for little rotete
#s26  print angle , sum
#s27  adjusted img,little rotated"

#s29  img///in getshape func now",
#s30  LF part

#s39  dsetroyAllWindows  in main end .

def  testStandingLying(mywidth,myheight,here_angle,count_in_BPH):
     if   min(mywidth, myheight) < 8  and count_in_BPH>12:  #small noise size, 8,9, 10
         return "no_too small"

     if min(mywidth,myheight)>0:
         if  max(mywidth,myheight)/min(mywidth,myheight)<1.35:
             return "no_like square"

     if mywidth < myheight:
         if here_angle>70:
             return "lying"
         elif here_angle<20:
             return "standing"
         else:
             return "no_angle not >70 or <20"
     else:
         if here_angle > 70:
             return "standing"
         elif here_angle < 20:
             return "lying"
         else:
             return "no_angle not >70 or <20"

def  testLying(mywidth,myheight,here_angle):
     if mywidth < myheight:
         if here_angle>45:
               # lying = lying + 1
             lying=True
         else:
               # standing = standing + 1
             lying=False
     else:
         if here_angle > 45:
                #standing = standing + 1
             lying = False
         else:
                #lying = lying + 1
             lying=True
     return lying
def int_to_str(int_num):
    lst = []
    s = ''
    while int_num > 0:
        num = int_num % 10
        lst.append(num)
        int_num //= 10

    for i in lst[::-1]:
        s += str(i)

    return s


def FillHole(im_in):


    # 复制 im_in 图像
    im_floodfill = im_in.copy()

    # Mask 用于 floodFill，官方要求长宽+2
    h, w = im_in.shape[:2]
    mask = np.zeros((h + 2, w + 2), np.uint8)

    # floodFill函数中的seedPoint必须是背景
    isbreak = False
    for i in range(im_floodfill.shape[0]):
        for j in range(im_floodfill.shape[1]):
            if (im_floodfill[i][j] == 0):
                seedPoint = (i, j)
                isbreak = True
                break
        if (isbreak):
            break
    # 得到im_floodfill
    cv2.floodFill(im_floodfill, mask, seedPoint, 255);

    # 得到im_floodfill的逆im_floodfill_inv
    im_floodfill_inv = cv2.bitwise_not(im_floodfill)
    # 把im_in、im_floodfill_inv这两幅图像结合起来得到前景
    im_out = im_in | im_floodfill_inv
    return im_out

def getMaxContourImg(image):
    contours, hierarchy = cv2.findContours(image,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
    contours = sorted(contours,key=lambda item:cv2.contourArea(item))
    x,y,w,h=cv2.boundingRect(contours[-1])  #???????? not minAreaRect ,but  just statstic state ,正姿态rect ?
    subImg =  image[y:y+h,x:x+w]
    return subImg

# refineRoi call   this  func,get LF image,   input  is large image ,return little image!!!!!???????
# no rotate !!!
def getRoiImage(image): #here image is one BPH image??, after   cv2.minAreaRect ->  crop_minAreaRect   rotate ,it is as large as  total pic  .
    contours, hierarchy = cv2.findContours(image,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) #
    contours = sorted(contours,key=lambda item:cv2.contourArea(item)) #all lines in  one  BPH,

    mask = np.zeros(image.shape,np.uint8)  # mask  ,as large  as image,,,,返回来一个给定形状和类型的用0填充的数组；
    cv2.drawContours(mask,[contours[-1]],-1,255,cv2.FILLED)  #
    #cv2.imshow("mask img", mask)
    #cv2.waitKey(0)
    kernel = np.ones((3,3), np.uint8)
    mask = cv2.erode(mask,kernel)    # filter

    x,y,w,h=cv2.boundingRect(contours[-1])  #在python中，数组的下标为-1代表数组的最后一个元素，下标为-2代表数组的倒数第二个元素，......。  ###  here   largest area  mean LF?
    ROI =  mask[y:y+h,x:x+w]   #large image become little image!!!!!?????
    return ROI

#only LF test  call  this func
def refineRoi(image):      #here image is LFimage, after   cv2.minAreaRect ->  crop_minAreaRect  , rotate_clock_direct   degree maybe happen!!!???      ,it is  large ,  most is blank , little  is LF  .
    #roiImage=image  ????
    roiImage=getRoiImage(image)  #???   # get LF rect ,  not  as large as total pic   ,,roiImage very little pic !!!!
    #cv2.imshow("input img", image)  #large
    ##cv2.waitKey(0)
    cv2.imshow("LF img,,,before adjust", roiImage)   #s24
    #cv2.waitKey(0)
    #roiImage = (image)
    center= (int(roiImage.shape[0]/2),int(roiImage.shape[1]/2))  #,roiImage very little pic !!!!     shape[0]  heigth  shape[1]  width

    targetShape = (roiImage.shape[0]*10,roiImage.shape[1]*10)    #dest size  (rows,cols))
    #targetShape = (roiImage.shape[0]*8 , roiImage.shape[1]*8 )

    hmax = max(int(roiImage.shape[0] / 2), int(roiImage.shape[1] / 2)) * 1.5  # 1.414
    center = (hmax, hmax)
    targetShape =(int(2.3*hmax), int(2.3*hmax))   #


    # 声明变换矩阵 向右平移10个像素， 向下平移30个像素
    #M = np.float32([[1, 0, 10], [0, 1, 30]])
    # 进行2D 仿射变换
    if roiImage.shape[0]>roiImage.shape[1]:  #veritical
        M = np.float32([[1, 0, int(hmax),], [0, 1, 0]])
        LF_looks_x_or_y="y"
        my_axis=0
    else:                                   #horizenal
        M = np.float32([[1, 0, 0], [0, 1, int(hmax)]])
        LF_looks_x_or_y="x"
        my_axis = 1
    shifted = cv2.warpAffine(roiImage, M, targetShape)
    cv2.imshow('shift_right_down ,prrepare for little rotete', shifted)   #s25
    ##cv2.waitKey(0)
##
    maxSum=0
    index=-1

    for i in range(180):#(90):           #    0  to 90 degree
        M = cv2.getRotationMatrix2D(center, -i, 1.0) #15   M matrix is unit ,   #getRotationMatrix2D(Point2f center, double angle, double scale)
        rotated = cv2.warpAffine(shifted, M, targetShape) #16 仿射变换  ,LF rotated, #### cv2.warpAffine(img,M,(rows,cols))
           #### cv2.warpAffine(src, M, dsize, dst=None, flags=None, borderMode=None, borderValue=None) --> dst

        '''
        if i%10==0:
            cv2.imshow("rotate img"+str(i), rotated)  #large
            cv2.waitKey(0)
            '''
        sumCols=rotated.sum(axis=my_axis)#1)      #axis=0, 表示列。axis=1, 表示行。   ##here i get sum from left to right!horrizonal sum!!!
        tmp=max(sumCols)
        if(tmp>maxSum):     # get max of maxSum_in_some_degree  ,     ,LF is most vertical or horizonal !!!  ????/
            maxSum=tmp
            index=i
        #print("maxcols",tmp, "i index",i,index)   #s26

    print("LF?? adjust angle==========================================",index)
    M = cv2.getRotationMatrix2D(center, -index, 1.0) #15    M matrix ,     #getRotationMatrix2D(Point2f center, double angle, double scale)
    #print("refineroi msg:",-index*2)
    rotatedRoi = cv2.warpAffine(roiImage, M, targetShape) #16
    rotatedRoi=getMaxContourImg(rotatedRoi)
    cv2.imshow("adjusted img,after little rotated "+str(index)+" degree", rotatedRoi)  #large   #s27
    ##cv2.waitKey(0)
    return rotatedRoi,index  # index  is  angle operate, clock direct.

# image is as large as total picture, but only one BPH appear!!!!(if reziseRATE ==1)
def getShape8b(image, BPH_angle_operated,BPHcx,BPHcy,width,height):

    cv2.imshow("getShape8b() BPH_angle_operated:"+str(BPH_angle_operated), image)  #s15
    ##cv2.waitKey(0)
    H,W=image.shape
    #image=image[int(0.03*H):int(0.97*H),int(0.03*W):int(0.97*W)]

    #contours, hierarchy = cv2.findContours(image,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
    #contours, hierarchy = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    contours, hierarchy = cv2.findContours(image, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)  # here contours ,is all lines  inner one BPH,(in image ,only one BPH appear!!!)
    num2=len(contours)
    print("in this BPH, len(contours)",num2,",H W",H,W)

    ##got BPH size:
    maxh=0
    maxw=0
    for item in contours:  # here contours ,is all lines  inner one BPH,(in image ,only one BPH appear!!!), here item is one line of one BPH.

        # mini Area ,!!!!   rect is more rilyable
        temp_rect = cv2.minAreaRect(item)
        temp_width = int(temp_rect[1][0])
        temp_height = int(temp_rect[1][1])
        if  temp_width >maxw:
            maxw=temp_width
        if  temp_height >maxh:
            maxh=temp_height
    ##end got BPH size, maxh maxw,
    #################erase noise
    erased=False
    href=maxh/30 # /10可以，/15   20  30 可以
    #####if href>penWidth???
    print(maxh,maxw,href)
    for item in contours:  # here contours ,is all lines  inner one BPH,(in image ,only one BPH appear!!!), here item is one line of one BPH.
        # get the rect image, test and erase ,H h n u  N -> ||
        (x, y, w, h) = cv2.boundingRect(item)
        if max(w,h)<maxw*7/10:# LF 不要参与erase ,防止 LF短线被误擦!!!!!!!!!!!!!!!!!!!!!!!
            (mm, nn, ss) = myfuncBPH.eraseBPHnoise(image[y:y + h, x:x + w], 1, href)
            if ss == "erased":
                erased = True
            cv2.imshow('now:after erase HhnuN', image)
        #cv2.waitKey(0)
        # end get,test
    if erased==True:#再发现一遍轮廓，
        contours, hierarchy = cv2.findContours(image, cv2.RETR_LIST,
                                               cv2.CHAIN_APPROX_SIMPLE)  # here contours ,is all lines  inner one BPH,(in image ,only one BPH appear!!!)
        num2 = len(contours)
        print("after erase HhnuN , in this BPH, len(contours)", num2, ",H W", H, W)

    ###################end erase


    shapeType="0"#L F
    shapeState="x_left" # b7 at x_left .
    shapecx_BPHcx=0
    shapecy_BPHcy=0
    mybitindex=0

    #prepeare  to  get pen width ,bit_size_reference
    pen_width=0
    #temp_min=[[0] for i in range(len(contours))]
    temp_min = [0] *(len(contours))  # here contours ,is all lines  inner one BPH,(in image ,only one BPH appear!!!)
    temp_all_height= [0] *(len(contours))
    temp_is_noise=[0] *(len(contours))
    temp_index=0

    if len(contours) < 9:  # here contours ,is all lines  inner one BPH,(in image ,only one BPH appear!!!)
        # 可能1像素 宽的 笔画。

        print("maybe  sub  too thin, inner, sub less than 9")
        return 1024



    for item in contours:    # here contours ,is all lines  inner one BPH,(in image ,only one BPH appear!!!), here item is one line of one BPH.

        # mini Area ,!!!!   rect is more rilyable
        temp_rect = cv2.minAreaRect(item)
        temp_width = int(temp_rect[1][0])
        temp_height = int(temp_rect[1][1])
        temp_min[temp_index ] = min(temp_height ,temp_width ) #min(h,w)
        temp_all_height[temp_index]=temp_height

        if  min(temp_height ,temp_width )>0:
            if max(temp_rect[1][0]/temp_rect[1][1],temp_rect[1][1]/temp_rect[1][0])<1.5:  #if  max(h/w,w/h)<1.5
            #if max(temp_width/temp_height,temp_height/temp_width)<1.5:#太接近 方块 ，就是 噪点 ，不是 笔画？？
                temp_is_noise[temp_index]=1
            else:
                temp_is_noise[temp_index] = 0
        if min(temp_height, temp_width) ==0:
            temp_is_noise[temp_index] = 1
        temp_index+=1

      #to get pen_width
    temp_index=0
    pen_width1=1
    pen_width2=1
    for iji in range (0, len(contours) ):   # here contours ,is all lines  inner one BPH,(in image ,only one BPH appear!!!),
        if temp_is_noise[iji]==0: #随意, 不是噪点 就可以。
             pen_width1=temp_min[iji]   #min(h,w)
             pen_width2=pen_width1

    max_height=temp_all_height[0]
    for item in contours:   # here contours ,is all lines  inner one BPH,(in image ,only one BPH appear!!!), here item is one line of one BPH.
        if temp_min[temp_index]<=pen_width1 and temp_is_noise[temp_index]==0:
            #pen_width2 倒数第二小的pen_width,在上边这行，必须小于等于，不能用小于。当8个 比特线 测试宽度 相等，可能会出错。
            #倒数第二小，希望可以过滤 一些干扰？？
            pen_width2 = pen_width1
            pen_width1=temp_min[temp_index]

        if temp_all_height[temp_index]>max_height:
            max_height=temp_all_height[temp_index]  #max_height
        temp_index+=1
    pen_width=pen_width2

    #得到 判断 是 比特线的 依据之一： 宽度小于它 ，就是 比特线，是画刷笔宽度乘以参数：大约2.5-3.5
    bit_size_width_reference = int(pen_width * 3)
    print("pen_width", pen_width, ",bit_size_width_reference", bit_size_width_reference)

    #  use  (get LF_height)    or  use max contour_height ,then get bit_size_reference比特最小高度(似乎，可以 过滤 小噪点)/
    # 注意， 用 LF突起 高度 也可 实现， 因为 带 外 整体 边界 ， 所以 暂时 不用之。暂时 用max_height得到 这些 参考。
    #bit_size_min_reference参数：0.075接近LF突起高度了，不要再小了，再小成点了。
    #bit_size_max_reference参数：0.6 就差不多要与LF接触了，不要再大了
    bit_size_min_reference=int(max_height*0.0715207)
    bit_size_max_reference = int(max_height * 0.61)
    print("bit_size_min_reference",bit_size_min_reference,",bit_size_max_reference",bit_size_max_reference)

    #bit_two_state_size_reference比特二态中间分界值
    bit_two_state_size_reference = int(max_height * 0.3389)#0.389
    print("bit_two_state_size_reference", bit_two_state_size_reference)
    #end prepare, ok


    ##########
    ##########
    #test lines in this BPH

    mybyteb_x=[([0] * 2) for i in range(8)]
    mybyteb_y = [([0] * 2) for i in range(8)]
    mem_LF_state=""

    testsuccess = "no"  #mark,,:
    itis = [(["no"]) for i in range(3200)]  # "bit"  "LF",,,,#200 ,noise count maybe more than 100, so use 200!!!!!!!  if camera is  1920 1200   , so more than 200, so use 1200!

    ##############
    print("getShape8b()  ,method of crossBand ,prepare: ")
    inCrossBandX=[(["no"]) for i in range(3200)]  # for "in" "out"
    inCrossBandY = [(["no"]) for i in range(3200)]  # for "in" "out"
    centerX=[([0]) for i in range(3200)]
    centerY = [([0]) for i in range(3200)]
    largestOneCenterX=0
    largestOneCenterY = 0
    largestH=0
    largestW = 0
    herei = 0
    for item in contours:  # here item is one line of one BPH.  maybe 11 12
        myrect = cv2.minAreaRect(item)

        centerX[herei]= int(myrect[0][0])
        centerY[herei] = int(myrect[0][1])
        mywidth = int(myrect[1][0])  # ?? width
        myheight = int(myrect[1][1])  # heigth
        #here_angle = -myrect[2]  # -90  -10...
        if  myheight > largestH:
            largestH=myheight
            largestW= mywidth
            largestOneCenterX=int(myrect[0][0])
            largestOneCenterY = int(myrect[0][1])

        herei = herei + 1
    print("contours count ===================================================" + str(len(contours)))

    herei = 0
    bandLeft= largestOneCenterX-largestW/6
    bandRight= largestOneCenterX + largestW / 6
    bandTop = largestOneCenterY - largestH / 6
    bandBottom = largestOneCenterY + largestH / 6
    xBandCount=0
    yBandCount=0
    crossBandCount=0
    or_xy_BandCount=0
    and_xy_BandCount = 0
    for item in contours:  # here item is one line of one BPH.  maybe 11 12
        if  centerX[herei]> bandLeft and  centerX[herei]< bandRight:
            inCrossBandY[herei] ="in"
            yBandCount += 1
            print("in-x band")
        if  centerY[herei]> bandTop and  centerY[herei]< bandBottom:
            inCrossBandX[herei] ="in"
            xBandCount += 1
            print("in-y band")
        if inCrossBandX[herei] == "in"  and  inCrossBandY[herei] =="in":
            and_xy_BandCount+=1
            print("in  both xy band happened")
        if inCrossBandX[herei] == "in"  or  inCrossBandY[herei] =="in":
            or_xy_BandCount+=1
            print("in  either xy band happened")
        herei = herei + 1
    print("kkkkkkkkk len(contours)=", len(contours)," xBandCount=", xBandCount, "yBandCount=" , yBandCount ,"or_xy_BandCount=",or_xy_BandCount,"and_xy_BandCount=",and_xy_BandCount,)
    #crossband prepare ok


    ########### "standing" "lying"   test :
    print("getShape8b()  ,method of  standing lying :")
    standing = 0#count
    lying = 0 #count
    LFislying = True
    theirResult= [(["no"]) for i in range(3200)]  # for "standing" "lying"            i in range(200)    i= 0 1 2 ....199

    herei=0
    for item in contours:  # here item is one line of one BPH.  maybe 11 12
        myrect = cv2.minAreaRect(item)
        mywidth = int(myrect[1][0])  # ?? width
        myheight = int(myrect[1][1])  # heigth
        here_angle=-myrect[2]  # -90  -10...

        result=testLying(mywidth,myheight,here_angle)
        r2= testStandingLying(mywidth,myheight,here_angle,len(contours))  #if len(contours) <=12  , not test thiness of line



        print("contours count ==================================================="+str(len(contours)))



        #theirResult[herei] =r2
        if r2 == "lying" and (inCrossBandY[herei] == "in"):
            theirResult[herei] =r2
        elif r2 == "standing" and (inCrossBandX[herei] == "in"):
            theirResult[herei] =r2


        #


        if r2=="lying" and (inCrossBandY[herei]=="in"):
            lying = lying + 1
        elif r2=="standing" and (inCrossBandX[herei]=="in"):
            standing = standing + 1
        #if r2!="no":
        #    print(mywidth, myheight, here_angle,standing,lying,"r2=",r2)

        print("w",mywidth, "H",myheight,"angle=", here_angle,"standingCount=",standing,"lyingCount=", lying, "r2=", r2)
        herei = herei + 1
















    ######################################
    ##  refresh   testsuccess  , standing>10  LFislying>10,, may happen!!!!!!!!!  many little  noise
    if standing==8  and lying==1:
        testsuccess="ok"
        LFislying = True
    elif standing == 1 and lying == 8:
        testsuccess = "ok"
        LFislying = False
    else:
        testsuccess="no"

    if standing == 8 and lying >1 and lying<8:
        testsuccess = "bit_ok"
        LFislying = True
    elif standing > 1 and  standing<8 and lying == 8:
        testsuccess = "bit_ok"
        LFislying = False
    elif standing == 1 and lying >8:
        testsuccess = "LF_ok"
        LFislying = False
    elif standing >8 and lying == 1:
        testsuccess = "LF_ok"
        LFislying = True
    elif min(standing,lying) ==0 or max(standing,lying)<8:
        testsuccess="fail"

    # refresh itis[]
    if  testsuccess=="ok":
        for ii in range(3200):
            if LFislying == True:
                if theirResult[ii]=="lying":
                    itis[ii]="LF"
                if theirResult[ii]=="standing":
                    itis[ii]="bit"
            if LFislying == False:
                if theirResult[ii] == "lying":
                    itis[ii] = "bit"
                if theirResult[ii] == "standing":
                    itis[ii] = "LF"
    if testsuccess == "bit_ok":  #LF still need test
        for ii in range(3200):
            if LFislying == True:
                if theirResult[ii] == "standing":
                    itis[ii] = "bit"
            if LFislying == False:
                if theirResult[ii] == "lying":
                    itis[ii] = "bit"
    if  testsuccess=="LF_ok":   #bit still need test
        for ii in range(3200):
            if LFislying == True:
                if theirResult[ii]=="lying":
                    itis[ii]="LF"
            if LFislying == False:
                if theirResult[ii] == "standing":
                    itis[ii] = "LF"

    print("zzzzzzzzzzzzzz len(contours)=", len(contours), "standing=",standing,"lying=",lying,"LFislying=",LFislying, "testsuccess=", testsuccess)
    print(itis)
    ###################
    ###################
    #go on test ,another mother ,line width test,
    print("getShape8b()  ,method of  line_width :")
    if testsuccess == "bit_ok":
        ii = 0
        for item in contours:  # here item is one line of one BPH.  maybe 11 12
            myrect = cv2.minAreaRect(item)
            mywidth = int(myrect[1][0])  # ?? width
            myheight = int(myrect[1][1])  # heigth
            myx = int(myrect[0][0])  # center x
            myy = int(myrect[0][1])  # center y
            # angle????myrect[2]
            print("w h", mywidth, myheight, "cx cy", myx, myy)
            heremin = min(mywidth, myheight)
            heremax = max(mywidth, myheight)

            print(heremin, bit_size_width_reference, "?>   ", heremax, heremin, "DIV   ?>3   ,if.. then LF found")
            if LFislying == True:
                if theirResult[ii] == "lying":
                    if  (heremin >= int(bit_size_width_reference)) and ((heremax / heremin) > 3):  # ???????heremin >= bit_size_width_reference????  = may happen when BPH is 45degree
                        itis[ii] = "LF"
            else:
                if theirResult[ii] == "standing":
                    if  (heremin >= int(bit_size_width_reference)) and ((heremax / heremin) > 3):  # ???????heremin >= bit_size_width_reference????  = may happen when BPH is 45degree
                        itis[ii] = "LF"
            ii = ii + 1
        #
        itisLFCnt=0
        for ii in range(3200):
            if itis[ii] == "LF":
                itisLFCnt=itisLFCnt+1
        #refresh testsuccess
        if  itisLFCnt==1:
            testsuccess="ok"

    elif testsuccess == "LF_ok":
        ii = 0
        for item in contours:  # here item is one line of one BPH.  maybe 11 12
            myrect = cv2.minAreaRect(item)
            mywidth = int(myrect[1][0])  # ?? width
            myheight = int(myrect[1][1])  # heigth
            myx = int(myrect[0][0])  # center x
            myy = int(myrect[0][1])  # center y
            # angle????myrect[2]
            print("w h", mywidth, myheight, "cx cy", myx, myy)
            heremin = min(mywidth, myheight)
            heremax = max(mywidth, myheight)

            print(heremin, bit_size_width_reference, "?>   ", heremax, heremin, "DIV   ?>3   ,if.. then LF found")
            if  LFislying == True:
                if theirResult[ii] == "standing":
                    if heremin <= bit_size_width_reference and heremax >= bit_size_min_reference and heremax <= bit_size_max_reference:
                        itis[ii] = "bit"
            else:
                if theirResult[ii] == "lying":
                    if heremin <= bit_size_width_reference and heremax >= bit_size_min_reference and heremax <= bit_size_max_reference:
                        itis[ii] = "bit"
            ii=ii+1
        #
        itisbitCnt = 0
        for ii in range(3200):
            if itis[ii] == "bit":
                itisbitCnt = itisbitCnt + 1
        # refresh testsuccess
        if itisbitCnt == 8:
            testsuccess = "ok"
    #end the test : line width test,

    '''
        ###################
        # go on test ,another mother ,in_crossBand  test ,
    print("getShape8b()  ,method of in_crossBand :")
    if testsuccess == "bit_ok":
        ii = 0
        for item in contours:  # here item is one line of one BPH.  maybe 11 12

            if LFislying == True:
                if theirResult[ii] == "lying":
                    if inCrossBandY[ii]=="in":
                        itis[ii] = "LF"
            else:
                if theirResult[ii] == "standing":
                    if  inCrossBandX[ii]=="in":
                        itis[ii] = "LF"
            ii = ii + 1
        #
        itisLFCnt = 0
        for ii in range(3200):
            if itis[ii] == "LF":
                itisLFCnt = itisLFCnt + 1
        # refresh testsuccess
        if itisLFCnt == 1:
            testsuccess = "ok"
            print ("in_crossBand test,do it ,ok")

    elif testsuccess == "LF_ok":
        ii = 0
        for item in contours:  # here item is one line of one BPH.  maybe 11 12

            if LFislying == True:
                if theirResult[ii] == "standing":
                    if inCrossBandX[ii]=="in":
                        itis[ii] = "bit"
            else:
                if theirResult[ii] == "lying":
                    if inCrossBandY[ii]=="in":
                        itis[ii] = "bit"
            ii = ii + 1
        #
        itisbitCnt = 0
        for ii in range(3200):
            if itis[ii] == "bit":
                itisbitCnt = itisbitCnt + 1
        # refresh testsuccess
        if itisbitCnt == 8:
            testsuccess = "ok"
            print("in_crossBand test,do it ,ok")
    #end the test :in_crossBand  test ,
    '''











    if testsuccess=="fail":
        print("find bit0-bit7 ,LF ,fail")


    ## success,    goon ,bit x y location ,LF shape
    if testsuccess == "ok":
        print("getShape8b(),successs, find bit0-bit7 ,LF ")
        mybitindex =0
        ii = 0
        for item in contours:  # here item is one line of one BPH.  maybe 11 12
            myrect = cv2.minAreaRect(item)
            mywidth = int(myrect[1][0])  # ?? width
            myheight = int(myrect[1][1])  # heigth
            myx = int(myrect[0][0])  # center x
            myy = int(myrect[0][1])  # center y
            # angle????myrect[2]
            print("w h", mywidth, myheight, "cx cy", myx, myy)
            heremin = min(mywidth, myheight)
            heremax = max(mywidth, myheight)

            # to get bit Value (prepare)
            if itis[ii]=="bit":
                print("get bit value ,bit loaction X y")
                if mybitindex < 8:
                    if heremax >= bit_two_state_size_reference:
                        # 二态系统之大感觉 态
                        mybyteb_x[mybitindex][1] = 1
                        mybyteb_y[mybitindex][1] = 1
                    if heremax < bit_two_state_size_reference:
                        # 二态系统 之 弱小感觉 态
                        mybyteb_x[mybitindex][1] = 0
                        mybyteb_y[mybitindex][1] = 0
                    mybyteb_x[mybitindex][0] = myx
                    mybyteb_y[mybitindex][0] = myy

                    print("bit index", mybitindex, "，bit value", mybyteb_x[mybitindex][1])
                    print(" ")
                mybitindex += 1
            if itis[ii] == "LF":
                print("test LF shape, LF state....")
                ##cv2.waitKey(0)
                LFrect = cv2.minAreaRect(
                    item)  # here item is one line of one BPH. (LF)  #because LF is not well like square ,minAreaRect  get the not correct angle LFrect[2]
                #  crop_minAreaRect( image ,LFrect,MYresizeRATE)   ,mean :clear other _lines of one BPH.only LF appear!!!!   image, black white total pic.
                # crop_minAreaRect include 转角 clock_direct_operate_angle (rect[2]  ) rotate!!
                # LFsubImg,_ = crop_minAreaRect(image,LFrect,2)
                LFsubImg= crop_minAreaRect(image, LFrect, 1)  # LFsubImg as large as  total pic if resizeRATE ==1,
                cv2.imshow("LFsubImg ", LFsubImg)  #s22
                ##cv2.waitKey(0)
                LF_operate_angle = -LFrect[2]  # LFrect[2]   is nagtive

                print("LF_operate_angle", LF_operate_angle)
                if (LFsubImg is not None):
                    # after crop_minAreaRect rotate, get LFsubImg , is  not correct enough!!! so  go on adjust,refineRoi :  max of max of sum vertical horizonal????????? ,adjust_angle, rotate it !

                    # now LFsubImg is equal_rect ???why,because after crop_minAreaRect ,u get it
                    LFsubImg_adjust, LF_adjust_angle_operated = refineRoi(
                        LFsubImg)  # ????什么用？ rotate ,test 0 to 180 degree ,(because LF is not well like square ,minAreaRect  get the not correct angle LFrect[2],,,so  go on ,adjust LF angle!!!!  very little ,near 0 degree or near 180
                    # now LFsubImg_adjust is smallest_rect ???why   refineRoi -> getRoiImage() ->findContours

                    print(" LF_operate_angle in minAreaRect", LF_operate_angle)
                    print("LF_adjust_angle_operated in refineRoi ", LF_adjust_angle_operated)
                    print("BPH_angle_operated", BPH_angle_operated)
                    shapeType, shapeState = get_LF_Shape(LFsubImg_adjust,pen_width)  # LFsubImg: LF line itself ,very small pic.!!!???
                    print("LF shapeType shapeState from getshape", shapeType, shapeState)
                    print("now  get the real LFstate:")
                    if LF_adjust_angle_operated > 170:  # near 180
                        if shapeState == "x_left":  # mean b7 is at left
                            shapeState = "x_right"
                        elif shapeState == "x_right":  # mean b7 is at right
                            shapeState = "x_left"
                        elif shapeState == "y_up":  # mean b7 is at up
                            shapeState = "y_down"
                        elif shapeState == "y_down":  # mean b7 is at down
                            shapeState = "y_up"

                    print("LF shapeType shapeState", shapeType, shapeState)
                    #cv2.waitKey(0)

                    if LF_operate_angle > 70:  # near 90
                        if shapeState == "x_left":  # mean b7 is at left
                            shapeState = "y_down"
                        elif shapeState == "x_right":  # mean b7 is at right
                            shapeState = "y_up"
                        elif shapeState == "y_up":  # mean b7 is at up
                            shapeState = "x_left"
                        elif shapeState == "y_down":  # mean b7 is at down
                            shapeState = "x_right"
                    mem_LF_state = shapeState   #  it  must before  " if BPH_angle_operated ....exe"
                    print("LF shapeType shapeState", shapeType, shapeState)
                    print("mem LF  shapeState", mem_LF_state)
                    # now   LFstate is saying , with the BPH_rotated  envirenment.
                    ''' no use????   
                    if BPH_angle_operated > 70:  # near      BPH_angle_operated is  when  BPH  crop....
                        if shapeState == "x_left":  # mean b7 is at left
                            shapeState = "y_down"
                        elif shapeState == "x_right":  # mean b7 is at right
                            shapeState = "y_up"
                        elif shapeState == "y_up":  # mean b7 is at up
                            shapeState = "x_left"
                        elif shapeState == "y_down":  # mean b7 is at down
                            shapeState = "x_right"
                
                    print("LF shapeType shapeState", shapeType, shapeState)
                    '''
                    LFshapex_BPHcx = LFrect[0][0] - BPHcx
                    LFshapey_BPHcy = LFrect[0][1] - BPHcy

                    print('LFshape is: ', shapeType, 'LFshapex_BPHcx', LFshapex_BPHcx, 'LFshapey_BPHcy', LFshapey_BPHcy)

            ii=ii+1
        print("bbbprepera   okokokokokkokokokokokokokokokok")

    '''
     
    '''

    #排序：(after prepare ,go on)
    #依据 x坐标 排序8个比特
    # 坐标 是 BPH rotated 后的，哦!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!shapeState 是 BPH rotated 后的!!!!
    print("now sort,////////shapeState=",shapeState, "   mem_LF_state=", mem_LF_state)
    mybyteb=[0]*8
    temp= mem_LF_state  #shapeState is  not  acurecy
    if temp == "x_left":  # mean b7 is at left
        mybyteb_x.sort()
        for bi in range(0, 8):
            mybyteb[bi] = mybyteb_x[bi][1]
    elif temp == "x_right":  # mean b7 is at right
        mybyteb_x.sort(reverse=True)
        for bi in range(0, 8):
            mybyteb[bi] = mybyteb_x[bi][1]
    elif temp == "y_up":  # mean b7 is at up
        mybyteb_y.sort()
        for bi in range(0, 8):
            mybyteb[bi] = mybyteb_y[bi][1]
    elif temp == "y_down":  # mean b7 is at down
        mybyteb_y.sort(reverse=True)
        for bi in range(0, 8):
            mybyteb[bi] = mybyteb_y[bi][1]





    print("mybyteb after sort", mybyteb, " cx-bitV  ",mybyteb_x," cy-bitV  ", mybyteb_y)

    #计算8个比特位的各个位代表值  之和，得到字节之值。
    mybytev=0
    # for ii in range(0, 8):  实际是 0 1 2 3 4 5 6 7 不带8不带最后一个 ，这个与vb不同。
    for ii in range(0, 8):
        if (mybyteb[ii]==1):
            mybytev+=2**(7-ii)
    print("mybytev:",mybytev)

    #增256：是 两个突起，像F。
    if (shapeType=='F'):
        mybytev +=256

    #若出错， 就用512表示
    if mybitindex!=8:
        mybytev=512

    return  mybytev

# for LF check, L or F   ,getShape8b call this func
def get_LF_Shape(image,penWidth):#image  is  LFimage, #not  as large as  total pic if resizeRATE ==1,!!!!!  but LF line itself ,very small pic.

    #???  if H>W  else:
    H, W = image.shape  # shape: height width channels
    print("LF:  H  W",H,W)
    #cv2.imshow("before half ", image)
    #cv2.waitKey(0)
    LFstate=""
    LFvalue=""
    '''
    ################
    image22 = image[0:H//2, :]  ##get upon part
    #cv2.imshow("upon half ", image22)
    #cv2.waitKey(0)
    contours, hierarchy = cv2.findContours(image22, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    #contours, hierarchy = cv2.findContours(image22, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    num = len(contours)
    ################
    image22 = image[H // 2:H, :]  ##get down part
    #cv2.imshow("down half ", image22)
    #cv2.waitKey(0)
    contours, hierarchy = cv2.findContours(image22, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    num2=len(contours)

    #print("LF",num)
    if(num==1)&(num2==1):
        LFvalue= "L"
    else:
        LFvalue= "F"
    ####
    '''



    cv2.imshow("img///in getshape func now,after little adjust", image) # 29
    ##cv2.waitKey(0)
    image22 = image[0:H // 2, 0:W//2]  ##get up left part
    cv2.imshow("LF part :up left", image22)       #s30
    ##cv2.waitKey(0)
    contours, hierarchy = cv2.findContours(image22, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    # contours, hierarchy = cv2.findContours(image22, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    num_up_left=0
    print("up left???????????????????????????"+str(len(contours)))
    for item in contours:#  noise    ,      very little noise , maybe 4 ||||| long part of "L" "F",  handwrite, not too line_like ,  so thin part will into   the Neighbourhood  empty quarter zone.
        (x, y, w, h) = cv2.boundingRect(item)  ## 找出轮廓包围的矩形框
        print((W,H) ,penWidth,w, h)
        #if max(item.shape[0],item.shape[1]) > min(H,W)/3  and   min( w, h)> penWidth/2 :
        if max(w,h) > min(H, W) / 3 and min(w, h) > penWidth / 2:
            num_up_left +=1
            #num_up_left = len(contours)

    image22 = image[H // 2:H, 0:W // 2]  ##get down left part
    cv2.imshow("LF part :down left", image22)
    ##cv2.waitKey(0)
    contours, hierarchy = cv2.findContours(image22, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    # contours, hierarchy = cv2.findContours(image22, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    num_down_left = 0
    print("down left???????????????????????????" + str(len(contours)))
    for item in contours:  # noise
        (x, y, w, h) = cv2.boundingRect(item)  ## 找出轮廓包围的矩形框
        print((W,H), penWidth, w, h)
        #if max(item.shape[0], item.shape[1]) > min(H, W) / 3   and   min( w, h)> penWidth/2  :
        if max(w, h) > min(H, W) / 3 and min(w, h) > penWidth / 2:
            num_down_left += 1
    #num_down_left = len(contours)

    image22 = image[0:H // 2, W // 2:W]  ##get up right part
    cv2.imshow("LF part :up right", image22)
    ##cv2.waitKey(0)
    contours, hierarchy = cv2.findContours(image22, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    # contours, hierarchy = cv2.findContours(image22, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    num_up_right = 0
    print("up right???????????????????????????" + str(len(contours)))
    for item in contours:  # noise
        (x, y, w, h) = cv2.boundingRect(item)  ## 找出轮廓包围的矩形框
        print((W,H), penWidth, w, h)
        #if max(item.shape[0], item.shape[1]) > min(H, W) / 3   and   min( w, h)> penWidth/2  :
        if max(w, h) > min(H, W) / 3 and min(w, h) > penWidth / 2:
            num_up_right += 1
    #num_up_right = len(contours)

    image22 = image[H // 2:H, W // 2:W]  ##get down right part
    cv2.imshow("LF part :down right", image22)
    ##cv2.waitKey(0)
    contours, hierarchy = cv2.findContours(image22, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    # contours, hierarchy = cv2.findContours(image22, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    num_down_right = 0
    print("down right???????????????????????????" + str(len(contours)))
    for item in contours:  # noise
        (x, y, w, h) = cv2.boundingRect(item)  ## 找出轮廓包围的矩形框
        print((W,H), penWidth, w, h)

        #if max(item.shape[0], item.shape[1]) > min(H, W) / 3   and   min( w, h)> penWidth/2  :
        if max(w, h) > min(H, W) / 3 and min(w, h) > penWidth / 2:
            num_down_right += 1
    #num_down_right = len(contours)

    #print("ul  dl   ur  dr", num_up_left,num_down_left, num_up_right,num_down_right ,)
    #cv2.waitKey(0)
    if H < W:            #lying

        if  num_up_left+num_down_left>=2 :
            LFstate = "x_left"
        else:
            LFstate = "x_right"
    else:               #standing

        if num_up_left +num_up_right >= 2:
            LFstate = "y_up"
        else:
            LFstate = "y_down"
    #########
    if H < W:  # lying

        if num_up_left + num_down_left == 2:
            LFvalue = "L"
        elif num_up_left + num_down_left > 2:
            LFvalue = "F"
        elif num_up_right + num_down_right == 2:
            LFvalue = "L"
        elif num_up_right + num_down_right > 2:
            LFvalue = "F"
    else:  # standing

        if num_up_left + num_up_right == 2:
            LFvalue = "L"
        elif num_up_left + num_up_right > 2:
            LFvalue = "F"
        if num_down_left + num_down_right == 2:
            LFvalue = "L"
        elif num_down_left + num_down_right > 2:
            LFvalue = "F"

    #########

    print("LFvalue, LFstate:  ", LFvalue, LFstate )
    print("num_up_left,   num_up_right  ",num_up_left,    num_up_right)
    print("num_down_left, num_down_right", num_down_left ,num_down_right)
    #cv2.waitKey(0)
    return  LFvalue, LFstate

    # here imagBW is   total pic ,  rect is for one BPH(or LF)(rect:center_x center_y w h angle), if resizeRATE==1:  return is  as large as  total pic (imageBW)   , without other BPH   only this BPH appear.!!!!
    # include 转角 clock_direct_operate_angle (rect[2] ) rotate!!
def crop_minAreaRect(imageBW, rect,resizeRATE):
    #resizeRATE 用 2 ，3 ，4 ， 5,6，  7， 8..越大越慢
    box = cv2.boxPoints(rect)
    box = np.int0(box)
    retW,retH=rect[1]   #???????H ,w
    H,W=imageBW.shape
    rectCenter = rect[0]
    angle = rect[2]#??-90  -80   -10...


    print("mask")
    mask=np.zeros(imageBW.shape,np.uint8)  # new, fill with 0
    cv2.drawContours(mask,[box],-1,255,cv2.FILLED)
    ROI = cv2.bitwise_and(imageBW,mask)  # and operate

    print("mask ok")
    #下面 转角angle (rect[2] ) ，可能，目的， 出图是：图案顺时针 转 rect[2]成 0度的样子?? angle大约等于 -45，-90 ，0
    M = cv2.getRotationMatrix2D(rectCenter, angle, 1.0)
    #截图，减少计算，提速


    #hy0= int(rect[0][1]-max(rect[1][0],rect[1][1])/2)-1
    #if hy0<0:
    #    hy0=0
    #hy1= int(rect[0][1]+max(rect[1][0],rect[1][1])/2)+1
    #
    #hx0= int(rect[0][0]-max(rect[1][0],rect[1][1])/2)-1
    #if hx0<0:
    #    hx0=0
    #hx1 = int(rect[0][0] + max(rect[1][0],rect[1][1])/2)+1


    #cv2.imshow("BWzzzz" +   str(hy0) + str(hy1) + str(hx0) + str(hx1), imageBW)
    #cv2.waitKey(0)


    #rect[1][0], rect[1][1]  H,W//////    rect[0][0], rect[0][1]  center, x y     same as (left  top)///// rect[2]  angle - singal
    thta=-rect[2]/360*2*math.pi
    outsideW=(rect[1][1])*math.cos(thta)+(rect[1][0])*math.sin(thta)
    outsideH=(rect[1][1]) * math.sin(thta) + (rect[1][0]) * math.cos(thta)
    outsideRadius=int((outsideW*outsideW+ outsideH* outsideH)**0.5 /2) # square
    """
    hy0 = int(rect[0][1] - outsideH / 2) - 1
    if hy0 < 0:
        hy0 = 0
    hy1= int(rect[0][1] + outsideH / 2) +1

    hx0 = int(rect[0][0] - outsideW / 2) - 1
    if hx0 < 0:
        hx0 = 0
    hx1 = int(rect[0][0] + outsideW / 2) + 1
    """
    hy0 = int(rect[0][1] - outsideRadius) - 1
    if hy0 < 0:
        hy0 = 0
    hy1 = int(rect[0][1] + outsideRadius) + 1

    hx0 = int(rect[0][0] - outsideRadius) - 1
    if hx0 < 0:
        hx0 = 0
    hx1 = int(rect[0][0] + outsideRadius) + 1

    #cv2.imshow("BWaaa"+str(math.cos(60))+ "W H:"+str(outsideW)+" "+str(outsideH),imageBW)
    #cv2.waitKey(0)
    #cv2.imshow("BWabbbb" + str(hy0)+" " + str(hy1) +" "+ str(hx0)+" " + str(hx1), imageBW)
    #cv2.waitKey(0)

    #lossless rotate enbalbe
    cropped = ROI[hy0:hy1, hx0:hx1] # 裁剪坐标为[y0:y1, x0:x1]     #ROI（region of interest）——感兴趣区域。
    #cv2.imshow("cropped" , cropped)
    #cv2.waitKey(0)
    #

    #ret = cv2.warpAffine(ROI, M, (H*resizeRATE,W * resizeRATE)) #这个太慢， 计算的任务太多，没必要,但是它是无损的？计算取整损耗？
    #HH=max(rect[1][0],rect[1][1])
    #WW=HH
    #M = cv2.getRotationMatrix2D((HH/2,WW/2), angle, 1.0)
    #ret = cv2.warpAffine(cropped, M, (H * resizeRATE, W * resizeRATE))#这个快，
    #return ret,0 #add90happened

    # ret = cv2.warpAffine(ROI, M, (H*resizeRATE,W * resizeRATE)) #这个太慢， 计算的任务太多，没必要,但是它是无损的？计算取整损耗？

    HH=outsideRadius*2
    WW=HH


    M = cv2.getRotationMatrix2D((outsideRadius,outsideRadius), angle, 1.0)
    ret = cv2.warpAffine(cropped, M,(HH,WW))## (HH * resizeRATE, WW * resizeRATE))#这个快，   resizeRATE?????? useless
    #cv2.imshow("ret"+str(resizeRATE), ret)
    #cv2.waitKey(0)
    return ret


def main(resizecode,imageRGB,showDialog):
    print( "opencv version ",cv2.__version__)
    #imageRGB = cv2.imread('test.jpg')

    #root = tkinter.Tk()
    #root.withdraw()  # 隐藏
    #root.update()  # 隐藏
    #对话框，可能 不太支持 汉字。
    #picfilename=tkinter.filedialog.askopenfilename(defaultextension = '.jpg',filetypes = [('all files', '.*'), ('jpg files', '.jpg')],initialdir= os.getcwd(),initialfile = 'test.jpg')
    #####picfilename = tkinter.filedialog.askopenfilename( initialdir=os.getcwd())
    #####imageRGB = cv2.imread(  picfilename)


    # 放大
    if resizecode!="normal":
        size = imageRGB.shape
        h, w = size[0], size[1]
        if h*w>1000000:  #############???????????????????????????????????????????????????????????????????
            scale =0.25#0.5# 2#3
        else:
            scale=2
        new_w, new_h = int(w * scale), int(h * scale)
        imageRGB = cv2.resize(imageRGB, (new_w, new_h),interpolation=cv2.INTER_CUBIC)
        print("resize happened")
    #放大结束，没起作用？ 起作用了。


    #图片尺寸
    sp=imageRGB.shape
    print("imagesize",sp[1],"*",sp[0])
    mypicH=sp[0]
    mypicW=sp[1]

    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))

    # 腐蚀图像
    erodeded =cv2.erode(imageRGB, kernel)
   # eroded = cv2.erode(erodeded, kernel)
    # 显示腐蚀后的图像
    ##cv2.imshow("Eroded Image", erodeded);

    # 膨胀图像 腐蚀图像
  ################### # dilated = cv2.dilate(imageRGB, kernel)
    # 显示膨胀后的图像
   # cv2.imshow("Dilated Image", dilated);


    # 原图像
   # cv2.imshow("Origin", imageRGB)     #s02
    #cv2.waitKey(0)


    image = cv2.cvtColor(erodeded, cv2.COLOR_BGR2GRAY)
    #image = cv2.cvtColor(dilated, cv2.COLOR_BGR2GRAY)
    # image = cv2.cvtColor(imageRGB,cv2.COLOR_BGR2GRAY)
    image = 255-image

    # 图像
    cv2.imshow("255-single", image)   #s03
    # cv2.waitKey(0)


    #(100,255  软件 出图 ，笔画色彩 淡薄 ，可 试 这个，；但是 对于 软件出图 然后拍照 屏幕，却 什么 都 识别 不出。)
    # (软件出图)70,255  （软件出图 然后 拍照屏幕 ,160 255；但是 软件 出图 的 色彩 淡薄的，却容易 不识别 。)
    _, BW = cv2.threshold(image, 160, 255, cv2.THRESH_BINARY )
    #_,BW = cv2.threshold(image,160,255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)
    #_, BW = cv2.threshold(image, 160, 255,  cv2.THRESH_OTSU)

    #BW=FillHole(BW22)
    #cv2.imshow("BW", BW)
    #cv2.waitKey(100)

    #素描图：
    imgG = cv2.GaussianBlur(image, (3, 3), 0)
    dst = cv2.Canny(imgG, 180, 180)  # 图片卷积——》th
    #BW=dst

    #素描之二
    #imgInfo = image.shape
    #height = imgInfo[0]
    #width = imgInfo[1]
    # sobel 1 算子模版 2 图片卷积 3 阈值判决
    # [1 2 1          [ 1 0 -1
    #  0 0 0            2 0 -2
    # -1 -2 -1 ]       1 0 -1 ]

    # [1 2 3 4] [a b c d] a*1+b*2+c*3+d*4 = dst

    #dst = np.zeros((height, width, 1), np.uint8)#创建
    #gray=image
    #print("okokokokok")
    #for i in range(0, height - 2):
    #    for j in range(0, width - 2):
    #        gy = gray[i, j] * 1 + gray[i, j + 1] * 2 + gray[i, j + 2] * 1 - gray[i + 2, j] * 1 - gray[
    #            i + 2, j + 1] * 2 - gray[i + 2, j + 2] * 1
    #        gx = gray[i, j] + gray[i + 1, j] * 2 + gray[i + 2, j] - gray[i, j + 2] - gray[i + 1, j + 2] * 2 - gray[
    #            i + 2, j + 2]
    #        grad = math.sqrt(gx * gx + gy * gy)
    #        if grad > 100:
    #            dst[i, j] = 0
    #        else:
    #            dst[i, j] = 255
    #BW=dst
    #print("ok12121212")


    #防止 照片太像条幅，导致画面右侧 轮廓检测 丢失 （不知为什么 ， cv2.findContours ）
    if mypicW/mypicH>2: #画面 增高
        img1=Image.fromarray(BW)
        # 创建一个新的图片对象
        newmypicH=int(mypicW/2)
        img2 = Image.new('RGB', (mypicW, newmypicH), (0, 0, 0))
        # 圈出需要复制的图片框(这里其实是复制img整个图片)
        box1 = (0, 0, mypicW, mypicH)
        # 按圈出的框复制图片
        region = img1.crop(box1)
        img2.paste(region, (0, 0))
        BW2= np.array(img2)
        BW = cv2.cvtColor(BW2, cv2.COLOR_BGR2GRAY)
        cv2.imshow("BW,height enlarge ,",BW)
        cv2.waitKey(100)
        mypicH = newmypicH
    else:
        cv2.imshow("BW", BW)  #s05
        cv2.waitKey(100)
    #BPH检测开始
    #contours, hierarchy = cv2.findContours(BW,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
    contours, hierarchy = cv2.findContours(BW,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)  #here:contours is all BPH s.
    number=0
    success_bph=0
    print("total bph may be:",len(contours))
    bhp_height=0
    mycache_x_y_v_LF= [([0] * 4) for i in range(len(contours))]
    mycache_BPHheight= [([0]) for i in range(len(contours))]
    linestartmem=[0]*len(contours)
    nextlinestartmem=[0]*len(contours)

    for item in contours:              #here:contours is all BPH s.
        #最小外接矩形 cv2.minAreaRect
        rect = cv2.minAreaRect(item)  #here rect is for one BPH , width (rect[1][0]),   height=int(rect[1][1]),angle rect[2],,, center_x ,rect[0][0],  center_y rect[0][1],
        #box = cv2.boxPoints(rect)
        #box = np.int0(box)

        width=int(rect[1][0])
        height=int(rect[1][1])
        #bph_height=height#不准 可能 某行 用小BPH , 某行 用大BPH , 所以 ，下面 做 更多判断。
        cx=int(rect[0][0]) #BPHcx  BPH centrel x
        cy=int(rect[0][1]) #BPHcy  BPH centrel y
        #?????? 过滤 ，10似乎 太小 ，用 30.
        if(min(width,height)>30 and rect[1][0]<mypicH and rect[1][1]<mypicH):
            number+=1
            #cv2.drawContours(imageRGB,[box],-1,(0,0,255))
            #boundingRect=cv2.boundingRect(item)
            print('this BPH angle ============================================================== ',rect[2])
            print("this BPH xywha",rect[0][0],rect[0][1],rect[1][0],rect[1][1],rect[2])
            bwh,bww=BW.shape

            print("before call  getshape8b,the total pic :BW",bww,bwh)
            print("before call  getshape8b,this one BPH,the minAreaRect  whxy", width,height,cx,cy)
            if min(width,height)<100 :#太小的BPH，要多放大。VB画的 大约是68宽度的,
                MYresizeRATE=3
                #elif min(width,height)>200:
                #    MYresizeRATE = 6
            else:
                MYresizeRATE=2
            if min(width, height) > 1000:  #太大的BPH,不要放大了
                MYresizeRATE = 1
            #  crop_minAreaRect(BW,rect,MYresizeRATE)   ,mean :clear other BPH.!!!!  BW, black white total pic.
            # crop_minAreaRect include 转角 clock_direct_operate_angle (rect[2] or rect[2]+90) rotate!!  if minArea_rect retW<retH: +90 happened
            subImg= crop_minAreaRect(BW,rect,MYresizeRATE)   #here rect is for one BPH,    here subImg is as large as  total pic without other BPH, only this BPH appear.!!!!
            bwh2, bww2 = subImg.shape

            print("before call  getshape8b,the cleared_sub pic without other BPH , as large as  total pic :subimg w h", bww2, bwh2)
            if(subImg is not None):                             #rect[2]  is -signal
                shapetype8b = getShape8b(subImg,-rect[2],cx,cy ,width,height)  #here rect is for one BPH,     here subImg is as large as  total pic without other BPH, only this BPH appear.!!!!
                if(shapetype8b<256): #find BPH with L
                    mycache_x_y_v_LF[success_bph][0] =cx
                    mycache_x_y_v_LF[success_bph][1] = cy
                    mycache_x_y_v_LF[success_bph][2] = shapetype8b
                    mycache_x_y_v_LF[success_bph][3]=1
                    mycache_BPHheight[success_bph]=height #判断是BPH ,赋值bph_height， 这样比较准，（还 存在 问题， 若 多个 BPH不 一样高，怎么办？？？）?????????????????????????????
                    success_bph+=1
                    print("success  to get a BPH,sum=",success_bph)
                if ((shapetype8b >= 256)and (shapetype8b <512)): #find BPH with F
                    mycache_x_y_v_LF[success_bph][0] = cx
                    mycache_x_y_v_LF[success_bph][1] = cy
                    mycache_x_y_v_LF[success_bph][2] = shapetype8b-256
                    mycache_x_y_v_LF[success_bph][3] = 2
                    mycache_BPHheight[success_bph] = height  # 判断是BPH ,赋值bph_height， 这样比较准，（还 存在 问题， 若 多个 BPH不 一样高，怎么办？？？）???????????????????????????????
                    success_bph += 1
                    print("success  to get a BPH,sum=", success_bph)

                if (shapetype8b == 512):
                     print("fail  to get a BPH")
                print(" ")
                print(" ")
                    # break
    print("test: ",number," BPH sum=",success_bph)
    print(" mycache_x_y_v_LF", mycache_x_y_v_LF)





    #sort
    mycache_v = [0] * (success_bph)
    mycache_LF = [0] * (success_bph)
    print("")
    print("my sort:")
    mycache_iii= [0]* (success_bph)
    mycache_iiiiii= [0] * (success_bph)
    tempx=0
    memiii=0
    tempy=0
    hereindex = 0
    heremax_y=0

    #暂时 用第一个y乘以2 ，够大了，。
    heremin_y= mycache_x_y_v_LF[0][1]*2
    tempy=heremin_y
    #得 整体 最小y
    for iii in range(0, (success_bph)):
        if tempy> mycache_x_y_v_LF[iii][1]:
            tempy=mycache_x_y_v_LF[iii][1]
            memiii=iii
    bph_height=mycache_BPHheight[memiii]
    print("min y i have got,memiii   tempy ",memiii ,tempy )
    print(" ")
    heremin_y=tempy
    memdelta2 =heremin_y

    linestart=0
    nextlinestart=0
    lines=0
    hereindex=0
    while hereindex<success_bph:
        #这个y 接近的 各个点 ，组成 一行line， 保存，也得到nextlinestart
        for iii in range(0, (success_bph)):
            #print("iii",iii)
            delta=mycache_x_y_v_LF[iii][1]-tempy
            if delta<(bph_height/2) and delta>=0:
                #print("iii-hereindex",hereindex)
                mycache_iiiiii[hereindex] = iii
                hereindex+=1
                print(iii)
        print("okok",bph_height/2)
        nextlinestart= hereindex
        linestartmem[lines]=linestart
        nextlinestartmem[lines]=nextlinestart


        #line  ,x 排序
        print ("linestart, nextlinestart",linestart,nextlinestart)
        for jjj in range(linestart, nextlinestart):
            #print(jjj,"jjj")
            for jj in range(linestart, nextlinestart-1):
                #print("jj",jj)
                if  mycache_x_y_v_LF[mycache_iiiiii[jj]][0] >mycache_x_y_v_LF[mycache_iiiiii[jj+1]][0]:
                    hi=mycache_iiiiii[jj]
                    mycache_iiiiii[jj]=mycache_iiiiii[jj+1]
                    mycache_iiiiii[jj+1]=hi


        for jjj in range(linestart, nextlinestart ):
            print("x=", mycache_x_y_v_LF[mycache_iiiiii[jjj]][0],"y=", mycache_x_y_v_LF[mycache_iiiiii[jjj]][1], "v=",mycache_x_y_v_LF[mycache_iiiiii[jjj]][2],"line=",lines)

        linestart = nextlinestart
        lines += 1


        memy=tempy
        memdelta2=10000  #heremax_y
         #得  剩余之 最小 y,赋值给tempy
        for iii in range(0, (success_bph)):
            delta2=  mycache_x_y_v_LF[ iii][1]-memy
            #print("mdelta2",memdelta2,"bph h",bph_height)
            if delta2>(bph_height/2):
                if delta2<memdelta2:
                    memdelta2=delta2
                    memiii=iii
                    tempy = mycache_x_y_v_LF[ iii][1]
        bhp_height = mycache_BPHheight[memiii]
        print("memiii   tempy(min y for this time) ", memiii, tempy)

    # redo,get mycache_v mycache_LF ,again
    for ij in  range(0, (success_bph)):
        mycache_v[ij]= mycache_x_y_v_LF[mycache_iiiiii[ij]][2]
        mycache_LF[ij]=mycache_x_y_v_LF[mycache_iiiiii[ij]][3]
    #测试打印
    print(" ")
    print("bph count:",success_bph ,",lines count:",lines)
    print("after sort，mycache_v", mycache_v, "mycache_LF", mycache_LF)

     ## for return !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    myba_hex_str=""
    myLF_hex_str=""
    l = [hex(int(i)) for i in mycache_v]
    myba_hex_str=" ".join(l)
    ll=[hex(int(i)) for i in mycache_LF]
    myLF_hex_str = " ".join(ll)
    print(  "mycache_v HEX:," ," ".join(l))
    print("mycache_LF HEX:,", " ".join(ll))

    #`o substitute :
    substitutestring=bytearray([0x30]*(success_bph*2))
    someb=b'0'
    someb2=b'0'
    someb3=b'0'
    for ijk in range(0,success_bph):
        someb= mycache_v[ijk]
        someb2=(someb & 15)
        someb2=someb2 |96
        someb3=(someb>>4)
        someb3 = someb3 | 96
        substitutestring[ijk*2] =someb3
        substitutestring[ijk * 2+1] = someb2
    print(" `o_substitutestring:",substitutestring.decode())
    print("show string ##############################################")
    str1 = ['0'] * (success_bph)
    for ii in range(0, success_bph):
        str1[ii] = chr(mycache_v[ii])
    str11 = ''.join('%s' % id for id in str1)
    print(str11)
    #
    print("show bytearray ##############################################")
    myba=bytearray([0x30]*success_bph)
    myba=bytearray(mycache_v)
    print("myba",myba)

    # draw,   mark mark mark mark mark mark mark mark mark mark mark mark mark mark mark mark mark mark

    location_str=""

    for iii in range(0, (success_bph)):
        drawx = mycache_x_y_v_LF[iii][0]
        drawy = mycache_x_y_v_LF[iii][1]
        ##for return !!!!!!!!!!!!!!!!!!!!!!!!
        location_str+=int_to_str(drawx)+" "+int_to_str(drawy)+";"

        htstr=hex(mycache_x_y_v_LF[iii][2]) # 类似  0xEF 的 样子 ，0xf 0xf0 0x0 0xff，
        if len(htstr)==3:
            htstr='0'+htstr[2:3]
            htstr=htstr.upper()
        else:
            htstr = htstr[2:4].upper()
        drawstr=htstr

        # 起点和终点的坐标
        ptStart = (drawx, drawy)
        ptEnd = (drawx + 10, drawy + 10)
        point_color = (0, 255, 0)  # BGR
        thickness = 1
        lineType = 4
        # cv2.line(imageRGB, ptStart, ptEnd, point_color, thickness, lineType)

        # 十六进制串  在图片添加文字，参数为，图片，绘制文字，位置，字体类型，字体大小，颜色，线条类型
        font = cv2.FONT_HERSHEY_SIMPLEX
        cv2.putText(imageRGB, drawstr, (drawx, drawy), font, 1, (0, 0, 127), 1)
        if mycache_x_y_v_LF[iii][3]==2:
            cv2.putText(imageRGB, drawstr, (drawx+5, drawy+5), font, 1, (0, 0, 127), 1)
        # char  ascii
        hb = bytearray([0] * 1)
        hb[0] = mycache_x_y_v_LF[iii][2]
        drawchr_ascii = hb.decode("ASCII", 'ignore')
        cv2.putText(imageRGB, drawchr_ascii, (drawx, drawy + 20), font, 1, (0, 127, 0), 1)

    #cv2.imshow("original,HEX chr pair,ASCII chr, "+picfilename, imageRGB)
    cv2.imshow("original,HEX chr pair,ASCII chr, " , imageRGB)
    #markedImg=imageRGB

    print("show all string  ##############################################")
    print("as ASCII charcode,print:")  # 'gb2312' 'gbk'  'utf-8' 'utf-16'
    myba2str = myba.decode("ASCII", 'replace')#'ignore')
    print(myba2str)
    print(" ")

    print("as utf_8 charcode,print:")
    #for return!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    suppose_str_utf_8=""
    myba2str=myba.decode("UTF-8",'replace')#'ignore')
    suppose_str_utf_8= myba2str
    print(myba2str)
    print(" ")
    #tkinter.messagebox.showinfo(str(success_bph)+',as utf-8,', myba2str)

    print("as GBK charcode,print:")  # 'gb2312' 'gbk'  'utf-8' 'utf-16'
    myba2str = myba.decode('GBK','replace')#'ignore')
    print(myba2str)
    print(" ")
    #tkinter.messagebox.showinfo('提示,as GBK,', myba2str)

    print("as unicode LE charcode,print:")  # 'gb2312' 'gbk'  'utf-8' 'utf-16'
    myba2str = myba.decode('utf_16_le', 'replace')#'ignore')  # 'ignore'   'strict'  'replace' 'xmlcharrefreplace'
    print(myba2str)
    print(" ")

    print("as unicode BE charcode,print:")  # 'gb2312' 'gbk'  'utf-8' 'utf-16'
    myba2str = myba.decode('utf_16_be','replace')# 'ignore')  # 'ignore'   'strict'  'replace' 'xmlcharrefreplace'
    print(myba2str)




    print("show  in lines @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ")

    linestr=['0123']*lines
    for kk in range(0, lines):
        str1 = ['0'] * (nextlinestartmem[kk] - linestartmem[kk])
        myba2 = bytearray([0x30] * (nextlinestartmem[kk] - linestartmem[kk]))
        tempindex = 0
        for ii in range(linestartmem[kk], nextlinestartmem[kk]):
            myba2[tempindex] = mycache_v[ii]
            tempindex += 1
            # myba.append(mycache_v[ii])

        linestr[kk] = myba2.decode("ASCII", 'ignore')
        print("linestr as ASCII ", linestr[kk])

    for kk in range(0, lines):
        myba2 = bytearray([0x30] * (nextlinestartmem[kk] - linestartmem[kk]))
        tempindex = 0
        for ii in range(linestartmem[kk], nextlinestartmem[kk]):
            myba2[tempindex] = mycache_v[ii]
            tempindex += 1
        linestr[kk] = myba2.decode("GBK", 'replace')#'strict')#'ignore')
        print("linestr as GBK ", linestr[kk])
    hstr = ''
    for kk in range(0, lines):
        hstr = hstr + linestr[kk] + '''\n'''
    if showDialog=="dialog":
        tkinter.messagebox.showinfo(str(success_bph) + ',as GBK,', hstr)



    for kk in range(0, lines):
        myba2 = bytearray([0x30] * (nextlinestartmem[kk] - linestartmem[kk]))
        tempindex = 0
        for ii in range(linestartmem[kk], nextlinestartmem[kk]):
            myba2[tempindex] = mycache_v[ii]
            tempindex += 1
        linestr[kk] = myba2.decode("UTF_8", 'replace')#'strict')#'ignore')
        print("linestr as UTF_8 ", linestr[kk])
    hstr=''
    for kk in range(0, lines):
        hstr=hstr+linestr[kk]+'''\n'''
    if showDialog == "dialog":
        tkinter.messagebox.showinfo(str(success_bph) + ',as utf-8,', hstr)

    for kk in range(0, lines):
        myba2 = bytearray([0x30] * (nextlinestartmem[kk] - linestartmem[kk]))
        tempindex = 0
        for ii in range(linestartmem[kk], nextlinestartmem[kk]):
            myba2[tempindex] = mycache_v[ii]
            tempindex += 1
        linestr[kk] = myba2.decode("UTF_16_LE", 'replace')# 'ignore')
        print("linestr as UTF_16_LE ", linestr[kk])


    for kk in range(0, lines):
        myba2 = bytearray([0x30] * (nextlinestartmem[kk] - linestartmem[kk]))
        tempindex = 0
        for ii in range(linestartmem[kk], nextlinestartmem[kk]):
            myba2[tempindex] = mycache_v[ii]
            tempindex += 1
        linestr[kk] = myba2.decode("UTF_16_BE",  'replace')#'ignore')
        print("linestr as UTF_16_BE", linestr[kk])

    print(resizecode+"  ok!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
    myall = str(success_bph)+"|"+"imagesize_w_h "+str(sp[1])+" "+str(sp[0])+"|"+location_str+"|" +myba_hex_str+"|"+myLF_hex_str+"|"+suppose_str_utf_8
    print(myall)
    print(" ")
    print(" ")
    print(" ")
   # root=tkinter.Tk()
    #root.withdraw()#隐藏
    #root.update()#隐藏
    #root.visible=0
    #txt=tkinter.messagebox.askyesno(success_bph,"ok?")
    #root.destroy()
    #cv2.waitKey(55000)

    #cv2.destroyAllWindows()   #s39
    print("all pictures  clear , !!!!!!!!!!!!!!!!!!!!!!!!!!!!!, u can input # upon line , so not clear ,u  can see detail!     search #s39 ,...")
    return success_bph,"imagesize_w_h "+str(sp[1])+" "+str(sp[0]),location_str, myba_hex_str,myLF_hex_str,suppose_str_utf_8,imageRGB#markedImg

# socket


if __name__ == "__main__":

   ######################     capture
    cap = cv2.VideoCapture(0,cv2.CAP_DSHOW)  #if  not 0  ,you can try 700
    print("capture初始化成功！")

    #savedpath = r'd:\\py\\'
    savedpath = os.getcwd()+'\\'
    print(savedpath )
    isExists = os.path.exists(savedpath)
    if not isExists:
        os.makedirs(savedpath)
        print('path of %s is build' % (savedpath))
    else:
        print('path of %s already exist and rebuild' % (savedpath))
    ret, frame = cap.read()

    cameraFound=True
    shoot = True
    if ret==False:
        shoot=False
        cameraFound =False
        print("camera 0  or 700 not found")

    herecnt=1000#30 10  #  delay 10 seconds,to form video, then , snap pic
    cv2.namedWindow("Image")
    while (shoot):
        ret, frame = cap.read()
        cv2.waitKey(200)
        if cv2.waitKey(100)&0xFF==ord('\x1b'):#(Key.esc):#('s'):
            shoot = False
        herecnt=herecnt-1
        if herecnt==0:
            shoot=False
        if shoot==True:
            font = cv2.FONT_HERSHEY_SIMPLEX
            cv2.putText(frame, str(herecnt) + "   Esc to snap ,exit", (60, 60), font, 1, (0, 0, 127), 1)
            cv2.imshow("Image", frame)

    savedname = 'camera_snap' + '.jpg'
    if cameraFound ==True:
        cv2.imwrite(savedpath + savedname, frame)
    cap.release()
    cv2.destroyAllWindows()
    ############      end capture




    #############################
    #socket
    ##def socket_service():


    #################### #  end  socket

    BPHlast=1111
    mylocation_str=""
    while 1==1:

        root = tkinter.Tk()
        root.withdraw()  # 隐藏 hide that little blank dialog
        root.update()  # 隐藏
        # 对话框，可能 不太支持 汉字。
        picfilename = tkinter.filedialog.askopenfilename(initialdir=os.getcwd())

        while picfilename=="":
            ######################     capture
            cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)  # if  not 0  ,you can try 700
            print("capture初始化成功！")

            # savedpath = r'd:\\py\\'
            savedpath = os.getcwd() + '\\'
            print(savedpath)
            isExists = os.path.exists(savedpath)
            if not isExists:
                os.makedirs(savedpath)
                print('path of %s is build' % (savedpath))
            else:
                print('path of %s already exist and rebuild' % (savedpath))
            ret, frame = cap.read()

            cameraFound = True
            shoot = True
            if ret == False:
                shoot = False
                cameraFound =False
                print("camera 0  or 700 not found")

            herecnt = 100  # 30  #  delay 10 seconds,to form video, then , snap pic
            cv2.namedWindow("Image")
            while (shoot):
                ret, frame = cap.read()

                cv2.waitKey(200)

                if cv2.waitKey(100) & 0xFF == ord('\x1b'):#('s'):
                    shoot = False
                herecnt = herecnt - 1
                if herecnt == 0:
                    shoot = False
                if shoot == True:
                    font = cv2.FONT_HERSHEY_SIMPLEX
                    cv2.putText(frame, str(herecnt) + "   Esc to snap ,exit", (60, 60), font, 1, (0, 0, 127), 1)
                    cv2.imshow("Image", frame)
            savedname = 'example' + '.jpg'
            if cameraFound == True:
                cv2.imwrite(savedpath + savedname, frame)
            cap.release()
            cv2.destroyAllWindows()
            ############      end capture

            root = tkinter.Tk()
            root.withdraw()  # 隐藏
            root.update()  # 隐藏
            # 对话框，可能 不太支持 汉字。
            picfilename = tkinter.filedialog.askopenfilename(initialdir=os.getcwd())

        cv2.destroyAllWindows()
        imageRGB = cv2.imread(picfilename)

        BPHlast,size_w_h,mylocation_str ,x_return,y_return,str_return,markedImg= main("normal", imageRGB,"nodialog")
        cv2.imshow('markedImg'+y_return+str_return, markedImg)
        ##cv2.waitKey(0)
        print("")
        print("size_W_H",size_w_h)
        print("location_str",mylocation_str)
        print("x_return",x_return)
        print("y_return",y_return)
        print("str_return",str_return)
        if BPHlast<1:#   <=1  BPH检测得 太少， 增一次 放大后检测。
            imageRGB = cv2.imread(picfilename)
            BPHlast,size_w_h,mylocation_str,x_return,y_return,str_return,markedImg=main("resize_again",imageRGB,"nodialog")
            cv2.imshow('markedImg resize again '+y_return+str_return, markedImg)
        ##cv2.waitKey(0)

        messagebox.showinfo("提示", "LF="+y_return+"\n"+"HEX:"+x_return+"\n"+str_return)
